package com.fqgj.sentry.policy.server;

import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.JSONUtils;
import com.fqgj.common.utils.StringUtils;
import com.fqgj.sentry.common.exception.BizException;
import com.fqgj.sentry.common.exception.enums.ErrorCodeEnums;
import com.fqgj.sentry.policy.client.PolicyExecutorService;
import com.fqgj.sentry.policy.dao.*;
import com.fqgj.sentry.policy.entity.*;
import com.fqgj.sentry.policy.enums.ActiveEnum;
import com.fqgj.sentry.policy.enums.ExecutorTypeEnum;
import com.fqgj.sentry.policy.enums.VersionStatusEnum;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: yujianfu (mr.vencnet@gmail.com)
 * Date: 2017/7/18
 * Time: 下午12:18
 */
@Service
public class PolicyExecutorServiceImpl implements PolicyExecutorService {

    @Autowired
    private PcExecutorDao pcExecutorDao;
    @Autowired
    private PcPolicyDao pcPolicyDao;
    @Autowired
    private PcRuleDao pcRuleDao;
    @Autowired
    private PcRuleColumnDao pcRuleColumnDao;
    @Autowired
    private PcRuleConditionDao pcRuleConditionDao;


    @Override
    public Long insertPolicyExecutor(PcExecutorEntity pcExecutorEntity) {
        //判断有没有待发布版本
        PcExecutorEntity executorEntity = pcExecutorDao.selectPcExecutorPending(pcExecutorEntity.getPolicySetsId(), pcExecutorEntity.getType());
        if (executorEntity != null) {
            throw new BizException(ErrorCodeEnums.policy_executor_is_error, "已经有待发布版本，无法再创建代发布版本");
        }
        pcExecutorDao.insertExecutor(pcExecutorEntity);
        return pcExecutorEntity.getId();
    }

    @Transactional
    @Override
    public Boolean copyPolicyExecutor(Long copyExecutorId, Long newExecutorId) {
        List<PcPolicyEntity> policyEntityList = pcPolicyDao.selectPolicyByExecutorId(copyExecutorId);
        PcExecutorEntity executorEntity = pcExecutorDao.selectByPrimaryKey(newExecutorId);
        //拷贝版本的执行者下的策略集查询出来
        for (PcPolicyEntity policyEntity : policyEntityList) {
            PcPolicyEntity newEntity = new PcPolicyEntity();
            BeanUtils.copyProperties(policyEntity, newEntity);
            newEntity.setExecutorId(newExecutorId);
            Long policyId = pcPolicyDao.insert(newEntity).getId();
            //拷贝策略下面的规则
            List<PcRuleEntity> ruleEntityList = pcRuleDao.selectListByPolicyId(policyEntity.getId(), ActiveEnum.all.getType(),com.fqgj.sentry.policy.enums.RuleTypeEnum.all.getType());
            for (PcRuleEntity ruleEntity : ruleEntityList) {
                PcRuleEntity newRuleEntity = new PcRuleEntity();
                BeanUtils.copyProperties(ruleEntity, newRuleEntity);
                newRuleEntity.setExecutorId(newExecutorId)
                        .setPolicyId(policyId);
                newRuleEntity.setVersion(executorEntity.getVersion());
                Long ruleId = pcRuleDao.insert(newRuleEntity).getId();
                //拷贝每个规则下面的对应的字段关系
                List<PcRuleColumnEntity> pcRuleColumnEntities = pcRuleColumnDao.findByRuleId(ruleEntity.getId());
                for (PcRuleColumnEntity columnEntity : pcRuleColumnEntities) {
                    PcRuleColumnEntity newColumnEntity = new PcRuleColumnEntity();
                    BeanUtils.copyProperties(columnEntity, newColumnEntity);
                    newColumnEntity.setRuleId(ruleId);
                    pcRuleColumnDao.insert(newColumnEntity);
                }
                PcRuleConditionEntity ruleConditionEntity = pcRuleConditionDao.selectByRuleId(ruleEntity.getId());
                if (ruleConditionEntity != null) {
                    PcRuleConditionEntity conditionEntity = new PcRuleConditionEntity();
                    BeanUtils.copyProperties(ruleConditionEntity, conditionEntity);
                    try {
                        if (StringUtils.isNotEmpty(conditionEntity.getFirstCondition())) {
                            conditionEntity.setFirstCondition(getNewCondition(ruleId, conditionEntity.getFirstCondition()));
                        }
                        if (StringUtils.isNotEmpty(conditionEntity.getWeightCondition())) {
                            conditionEntity.setWeightCondition(getNewCondition(ruleId, conditionEntity.getWeightCondition()));
                        }
                        if (StringUtils.isNotEmpty(conditionEntity.getWorstCondition())) {
                            conditionEntity.setWorstCondition(getNewCondition(ruleId, conditionEntity.getWorstCondition()));
                        }
                        if (StringUtils.isNotEmpty(conditionEntity.getScoreCondition())) {
                            conditionEntity.setScoreCondition(getNewCondition(ruleId, conditionEntity.getScoreCondition()));
                        }
                    } catch (Exception e) {
                        throw new BizException(ErrorCodeEnums.json_transform_error);
                    }
                    conditionEntity.setRuleId(ruleId)
                            .setPolicyId(policyId);
                    pcRuleConditionDao.insert(conditionEntity);
                }
            }
        }
        return true;
    }

    private String getNewCondition(Long ruleId, String oldCondition) {
        String newCondition = "";
        try {
            Map conditionMap = new HashMap();
            conditionMap = JSONUtils.json2map(oldCondition);
            conditionMap.put("ruleId", ruleId);
            newCondition = JSONUtils.obj2json(conditionMap);
        } catch (Exception e) {
            throw new BizException(ErrorCodeEnums.json_transform_error);
        }
        return newCondition;
    }

    @Override
    public Boolean deletePolicyExecutor(Long executorId) {
        checkPolicyExecutor(executorId);
        List<PcPolicyEntity> policyEntityList = pcPolicyDao.selectPolicyByExecutorId(executorId);
        if (CollectionUtils.isNotEmpty(policyEntityList)) {
            throw new BizException(ErrorCodeEnums.policy_executor_has_policy_error);
        }
        pcExecutorDao.deleteByPrimaryKey(executorId);
        return true;
    }

    @Override
    public Boolean updatePolicyExecutorInfo(Long executorId, String info) {
        PcExecutorEntity executorEntity = pcExecutorDao.selectByPrimaryKey(executorId);
        if (executorEntity == null || !executorEntity.getVersionStatus().equals(VersionStatusEnum.pending_version.getStatus())) {
            throw new BizException(ErrorCodeEnums.policy_executor_not_error, "该版本不是待发布版本，无法修改详情");
        }
        executorEntity.setInfo(info);
        pcExecutorDao.updateByPrimaryKey(executorEntity);
        return true;
    }

    /**
     * 丢弃 待发布版本
     *
     * @param executorId
     * @return
     */
    @Override
    public Boolean dropPolicyExecutor(Long executorId) {
        //判断 是否 为待发布版本
        PcExecutorEntity executorEntity = pcExecutorDao.selectByPrimaryKey(executorId);
        if (executorEntity == null || !executorEntity.getVersionStatus().equals(VersionStatusEnum.pending_version.getStatus())) {
            throw new BizException(ErrorCodeEnums.policy_executor_not_error, "该版本不是待发布版本~");
        }
        executorEntity.setVersionStatus(VersionStatusEnum.drop_version.getStatus());
        executorEntity.setDeleted(true);
        return pcExecutorDao.updateByPrimaryKey(executorEntity) > 0;
    }

    @Override
    public Boolean setExecutorSwitch(Long executorId, Integer open) {

        PcExecutorEntity executorEntity = checkPolicyExecutor(executorId);
        executorEntity.setIsActive(open);
        pcExecutorDao.updateByPrimaryKey(executorEntity);
        return true;
    }

    @Override
    public Boolean setChallengerExecutorPercent(Long executorId, Integer percent) {
        PcExecutorEntity executorEntity = checkPolicyExecutor(executorId);
        if (!executorEntity.getType().equals(ExecutorTypeEnum.challenger.getType())) {
            throw new BizException(ErrorCodeEnums.policy_executor_is_error, "当前的执行者不是挑战者版本，只有挑战者才能设置占比");
        }
        executorEntity.setExecutePercent(percent);
        pcExecutorDao.updateByPrimaryKey(executorEntity);
        return true;
    }

    @Override
    public Boolean rollBackExecutor(Long executorId) {
        PcExecutorEntity executorEntity = checkRollBackExecutor(executorId);
        //先将线上版本设置为历史版本
        pcExecutorDao.updateExecutorToHistory(executorEntity.getPolicySetsId(), executorEntity.getType());
        //再重新设置executor回滚的版本为线上版本
        executorEntity.setVersionStatus(VersionStatusEnum.current_version.getStatus());
        pcExecutorDao.updateByPrimaryKey(executorEntity);
        return true;
    }

    @Override
    public Boolean releaseExecutor(Long executorId) {
        PcExecutorEntity executorEntity = checkPendingExecutor(executorId);
        //先将线上版本设置为历史版本
        pcExecutorDao.updateExecutorToHistory(executorEntity.getPolicySetsId(), executorEntity.getType());
        //再设置当前要发布的版本为线上版本
        executorEntity.setVersionStatus(VersionStatusEnum.current_version.getStatus());
        executorEntity.setPublishDate(new Date());
        pcExecutorDao.updateByPrimaryKey(executorEntity);
        return true;
    }

    @Override
    public PcExecutorEntity selectPcExecutorCurrent(Long policySetsId, Integer executorType, Integer active) {
        return pcExecutorDao.selectPcExecutorCurrent(policySetsId, executorType, active);
    }

    @Override
    public List<PcExecutorEntity> selectPcExecutorHistoryList(Long policySetsId, Integer type) {
        return pcExecutorDao.selectPcExecutorHistoryList(policySetsId, type);
    }

    @Override
    public PcExecutorEntity selectPcExecutorPending(Long policySetsId, Integer type) {
        return pcExecutorDao.selectPcExecutorPending(policySetsId, type);
    }

    private PcExecutorEntity checkPolicyExecutor(Long executorId) {
        PcExecutorEntity executorEntity = pcExecutorDao.selectByPrimaryKey(executorId);
        if (executorEntity == null || executorEntity.getDeleted()
                || executorEntity.getVersionStatus().equals(VersionStatusEnum.history_version.getStatus())) {
            throw new BizException(ErrorCodeEnums.policy_executor_not_error);
        }
        return executorEntity;
    }

    private PcExecutorEntity checkRollBackExecutor(Long executorId) {
        PcExecutorEntity executorEntity = pcExecutorDao.selectByPrimaryKey(executorId);
        if (executorEntity == null || executorEntity.getDeleted()) {
            throw new BizException(ErrorCodeEnums.policy_executor_not_error, "回滚的执行者不存在");
        }
        if (executorEntity.getVersionStatus().equals(VersionStatusEnum.current_version.getStatus())) {
            throw new BizException(ErrorCodeEnums.policy_executor_is_error, "该版本已经是线上版本无需回滚");
        }
        if (executorEntity.getVersionStatus().equals(VersionStatusEnum.pending_version.getStatus())) {
            throw new BizException(ErrorCodeEnums.policy_executor_is_error, "该版本是待发布版本无法回滚");
        }
        return executorEntity;
    }

    private PcExecutorEntity checkPendingExecutor(Long executorId) {
        PcExecutorEntity executorEntity = pcExecutorDao.selectByPrimaryKey(executorId);
        if (executorEntity == null || executorEntity.getDeleted()) {
            throw new BizException(ErrorCodeEnums.policy_executor_not_error, "要发布执行者不存在");
        }
        if (!executorEntity.getVersionStatus().equals(VersionStatusEnum.pending_version.getStatus())) {
            throw new BizException(ErrorCodeEnums.policy_executor_not_error, "要发布的执行者不是待发布版本无法发布");
        }
        return executorEntity;
    }

    @Override
    public List<PcExecutorEntity> selectPcCurrentAllExecutor(Long policySetsId) {
        List<PcExecutorEntity> pcExecutorEntityList = pcExecutorDao.selectListByPolicySetId(policySetsId);
        return pcExecutorEntityList;
    }

    /**
     * 根据执行者 查询
     *
     * @param executorId
     * @return
     */
    @Override
    public PcExecutorEntity selectByExecutorId(Long executorId) {
        return pcExecutorDao.selectByPrimaryKey(executorId);
    }
}
